#include "lfs.h"
#include "spi_flash.h"
#include "log.h"
#include "lfs_port.h"


uint16_t curve[Len_curve];
uint16_t bake_ctrl[Len_bake_ctrl];


static int lfs_deskio_read(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, void *buffer, lfs_size_t size)
{
    SPIFLASH_read(0, (uint8_t *)buffer, c->block_size * block + off, size);
    return LFS_ERR_OK;
}
static int lfs_deskio_prog(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, const void *buffer, lfs_size_t size)
{
    SPIFLASH_write(0, (uint8_t *)buffer, c->block_size * block + off, size);
    return LFS_ERR_OK;
}
static int lfs_deskio_erase(const struct lfs_config *c, lfs_block_t block)
{
    SPIFLASH_eraseSector(0, block);
    return LFS_ERR_OK;
}
static int lfs_deskio_sync(const struct lfs_config *c)
{
    return LFS_ERR_OK;
}

__align(4) static uint8_t read_buffer[16];
__align(4) static uint8_t prog_buffer[16];
__align(4) static uint8_t lookahead_buffer[16];


lfs_t lfs_w25qxx;
lfs_file_t lfs_file_w25qxx;

const struct lfs_config cfg =
{
    // block device operations
    .read  = lfs_deskio_read,
    .prog  = lfs_deskio_prog,
    .erase = lfs_deskio_erase,
    .sync  = lfs_deskio_sync,

    // block device configuration
    .read_size = 16,
    .prog_size = 16,
    .block_size = 4096,
    .block_count = 512,
    .cache_size = 16,
    .lookahead_size = 16,
    .block_cycles = 512,

    .read_buffer = read_buffer,
    .prog_buffer = prog_buffer,
    .lookahead_buffer = lookahead_buffer,
};

// entry point
void lfs_program(void)
{
    LOG_FUNC();
    // mount the filesystem
    int err = lfs_mount(&lfs_w25qxx, &cfg);
    // reformat if we can't mount the filesystem
    // this should only happen on the first boot
    if (err)
    {
        lfs_format(&lfs_w25qxx, &cfg);
        lfs_mount(&lfs_w25qxx, &cfg);
    }

    // read current count
    uint32_t boot_count = 0;
    lfs_file_open(&lfs_w25qxx, &lfs_file_w25qxx, "boot_count", LFS_O_RDWR | LFS_O_CREAT);

    lfs_file_rewind(&lfs_w25qxx, &lfs_file_w25qxx);
    lfs_file_read(&lfs_w25qxx, &lfs_file_w25qxx, &boot_count, sizeof(boot_count));

    // update boot count
    boot_count += 1;
    lfs_file_rewind(&lfs_w25qxx, &lfs_file_w25qxx);
    lfs_file_write(&lfs_w25qxx, &lfs_file_w25qxx, &boot_count, sizeof(boot_count));
    // print the boot count
    LOG_DEBUG("BOOT_COUNT: %d\r\n", boot_count);

    // remember the storage is not updated until the file is closed successfully
    lfs_file_close(&lfs_w25qxx, &lfs_file_w25qxx);
    // release any resources we were using
    lfs_unmount(&lfs_w25qxx);

}

HAL_StatusTypeDef lfs_user(const char *path, uint16_t *data, uint16_t len, lfs_op op)
{
    if((op != Lfs_Read)&&(op != Lfs_Write)) {
        return HAL_ERROR;
    }
    // mount the filesystem
    int err = lfs_mount(&lfs_w25qxx, &cfg);
    // reformat if we can't mount the filesystem
    // this should only happen on the first boot
    if (err)
    {
        lfs_format(&lfs_w25qxx, &cfg);
        lfs_mount(&lfs_w25qxx, &cfg);
    }
    if(op == Lfs_Read) {
        lfs_file_open(&lfs_w25qxx, &lfs_file_w25qxx, path, LFS_O_RDWR | LFS_O_CREAT);
        lfs_file_rewind(&lfs_w25qxx, &lfs_file_w25qxx);
        lfs_file_read(&lfs_w25qxx, &lfs_file_w25qxx, &data[0], sizeof(int)*len);
        LOG_DEBUG("Lfs_Read %s \r\n", path);
    }
    if(op == Lfs_Write) {
        lfs_file_open(&lfs_w25qxx, &lfs_file_w25qxx, path, LFS_O_RDWR | LFS_O_CREAT);
        lfs_file_rewind(&lfs_w25qxx, &lfs_file_w25qxx);
        lfs_file_write(&lfs_w25qxx, &lfs_file_w25qxx, &data[0], sizeof(int)*len);
        LOG_DEBUG("Lfs_Write %s \r\n", path);
    }

    // remember the storage is not updated until the file is closed successfully
    lfs_file_close(&lfs_w25qxx, &lfs_file_w25qxx);
    // release any resources we were using
    lfs_unmount(&lfs_w25qxx);
    return HAL_OK;

}